package se.thoka.twt.client.utils;

import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author Thobias Karlsson, Thoka
 * @since 8 jan 2010
 */
public class CSS {
	/** The style concatenation character */
	public static final char CONCAT_CHAR = '-';

	/**
	 * Has specific style name
	 */
	public interface HasStyle {
		/**
		 * @return The style name
		 */
		String getStyle();

		/**
		 * Adds this style to the supplied widget
		 * 
		 * @param w The widget, must not be <code>null</code>
		 */
		void addTo(Widget w);

		/**
		 * Removes this style from the supplied widget
		 * 
		 * @param w The widget, must not be <code>null</code>
		 */
		void removeFrom(Widget w);

		/**
		 * Sets this style to the supplied widget
		 * 
		 * @param w The widget, must not be <code>null</code>
		 */
		void setTo(Widget w);

		/**
		 * Adds/removes this style to the supplied widget
		 * 
		 * @param w The widget, must not be <code>null</code>
		 * @param active Set <code>true</code> to add style and <code>false</code> to remove it
		 */
		void setTo(Widget w, boolean active);

		/**
		 * Sets this style as primary style name to the supplied widget
		 * 
		 * @param w The widget, must not be <code>null</code>
		 */
		void setPrimaryTo(Widget w);
	}

	/**
	 * Has style dependent name
	 */
	public interface HasStyleDependentName {
		/**
		 * Sets this style dependent name active/inactive on the supplied widget.
		 * 
		 * @param w The widget, must not be <code>null</code>
		 * @param active Set <code>true</code> to add this style name and <code>false</code> to remove it
		 */
		void setDependentTo(Widget w, boolean active);
	}

	/**
	 * State style name suffix
	 */
	public static enum State implements HasStyle, HasStyleDependentName {
		/** Over */
		OVER("over"),
		/** Down */
		DOWN("down"),
		/** Open */
		OPEN("open"),
		/** Focus */
		FOCUS("focus"),
		/** Invalid */
		INVALID("invalid"),
		/** Disabled */
		DISABLED("disabled"),
		/** Required */
		REQUIRED("required"),
		/** Selected */
		SELECTED("selected"),
		/** Stripe */
		STRIPE("stripe"),
		/** Empty */
		EMPTY("empty");

		private final String style;

		private State(String style) {
			this.style = style;
		}

		@Override
		public String getStyle() {
			return style;
		}

		@Override
		public void addTo(Widget w) {
			w.addStyleName(getStyle());
		}

		@Override
		public void removeFrom(Widget w) {
			w.removeStyleName(getStyle());
		}

		@Override
		public void setTo(Widget w) {
			w.setStyleName(getStyle());
		}

		@Override
		public void setTo(Widget w, boolean active) {
			setStyle(w, this, active);
		}

		@Override
		public void setPrimaryTo(Widget w) {
			w.setStylePrimaryName(getStyle());
		}

		@Override
		public void setDependentTo(Widget w, boolean active) {
			setStyleDependentName(w, this, active);
		}
	}

	/**
	 * Position style names
	 */
	public static enum Position implements HasStyle, HasStyleDependentName {
		/** Left */
		LEFT(!LocaleInfo.getCurrentLocale().isRTL() ? "left" : "right"),
		/** Right */
		RIGHT(!LocaleInfo.getCurrentLocale().isRTL() ? "right" : "left"),
		/** Top */
		TOP("top"),
		/** Bottom */
		BOTTOM("bottom"),
		/** Center */
		CENTER("center"),
		/** Middle */
		MIDDLE("middle");

		private final String styleName;

		private Position(String styleName) {
			this.styleName = styleName;
		}

		@Override
		public String getStyle() {
			return styleName;
		}

		@Override
		public void addTo(Widget w) {
			w.addStyleName(getStyle());
		}

		@Override
		public void removeFrom(Widget w) {
			w.removeStyleName(getStyle());
		}

		@Override
		public void setTo(Widget w) {
			w.setStyleName(getStyle());
		}

		@Override
		public void setTo(Widget w, boolean active) {
			setStyle(w, this, active);
		}

		@Override
		public void setPrimaryTo(Widget w) {
			w.setStylePrimaryName(getStyle());
		}

		@Override
		public void setDependentTo(Widget w, boolean active) {
			setStyleDependentName(w, this, active);
		}
	}

	/**
	 * Panel style names
	 */
	public static enum Panel implements HasStyle {
		/** Scroll panel */
		SCROLL_PANEL("thoka-ScrollPanel"),
		/** Popup box panel */
		POPUP_BOX("thoka-PopupBox");

		private final String style;

		private Panel(String style) {
			this.style = style;
		}

		@Override
		public String getStyle() {
			return style;
		}

		@Override
		public void addTo(Widget w) {
			w.addStyleName(getStyle());
		}

		@Override
		public void removeFrom(Widget w) {
			w.removeStyleName(getStyle());
		}

		@Override
		public void setTo(Widget w) {
			w.setStyleName(getStyle());
		}

		@Override
		public void setTo(Widget w, boolean active) {
			setStyle(w, this, active);
		}

		@Override
		public void setPrimaryTo(Widget w) {
			w.setStylePrimaryName(getStyle());
		}
	}

	/**
	 * Adds/removes a style name on a widget
	 * 
	 * @param w The widget, must not be <code>null</code>
	 * @param style The style, must not be <code>null</code>
	 * @param active Set <code>true</code> to add style and <code>false</code> to remove
	 */
	public static void setStyle(Widget w, HasStyle style, boolean active) {
		setStyle(w, style.getStyle(), active);
	}

	/**
	 * Adds/removes a style name on a widget
	 * 
	 * @param w The widget, must not be <code>null</code>
	 * @param style The style, must not be <code>null</code>
	 * @param active Set <code>true</code> to add style and <code>false</code> to remove
	 */
	public static void setStyle(Widget w, String style, boolean active) {
		if (active) {
			w.addStyleName(style);
		} else {
			w.removeStyleName(style);
		}
	}

	/**
	 * Sets a style dependent name on a widget.
	 * 
	 * @param w The widget, must not be <code>null</code>
	 * @param styleSuffix The style suffix, must not be <code>null</code>
	 * @param active Set <code>true</code> to add style suffix or <code>false</code> to remove it.
	 */
	public static void setStyleDependentName(Widget w, HasStyle styleSuffix, boolean active) {
		setStyleDependentName(w, styleSuffix.getStyle(), active);
	}

	/**
	 * Sets a style dependent name on a widget.
	 * 
	 * @param w The widget, must not be <code>null</code>
	 * @param styleSuffix The style suffix, must not be <code>null</code>
	 * @param active Set <code>true</code> to add style suffix or <code>false</code> to remove it.
	 */
	public static void setStyleDependentName(Widget w, String styleSuffix, boolean active) {
		if (active) {
			w.addStyleDependentName(styleSuffix);
		} else {
			w.removeStyleDependentName(styleSuffix);
		}
	}

	/**
	 * Concatenates a style name with suffixes.
	 * <p>
	 * <ul>
	 * <li><code>concat("thokaBox")</code> will produce "<code>thokaBox</code>".</li>
	 * <li><code>concat("thokaBox", {@link Position#TOP})</code> will produce "<code>thokaBox-top</code>".</li>
	 * <li><code>concat("thokaBox", {@link Position#TOP}, {@link Position#LEFT})</code> will produce "<code>thokaBox-topleft</code>".</li>
	 * </ul>
	 * </p>
	 * 
	 * @param style The primary style prefix, must not be <code>null</code>
	 * @param suffixes The style suffix(es)
	 * @return The concatenated style name
	 */
	public static String concat(String style, HasStyle... suffixes) {
		if (style == null) {
			throw new NullPointerException("Style name must not be null");
		}

		if (suffixes.length > 0) {
			style += CONCAT_CHAR;
			for (HasStyle s : suffixes) {
				style += s.getStyle();
			}
		}

		return style;
	}
}
